<?php

/**
 * Class used to interact with roles returned by EVE API.
 * Other files included with this to assist:
 *
 * @author Steve Ousley <steve.ousley@gmail.com>
 * @copyright Copyright (c) 2011, Steve Ousley
 * @version 0.1
 * @package eveApi
 *
 */

/**
 * class Account
 * @package eveApi
 *
 */
class eveapi{
		
	/**
	* apiKey
	* String containing the apiKey to use for the Eve API
	*
	* @see __construct()
	* @see setApiCredentials
	*
	* @var String put your default apiKey here
	*/
	private $apiKey="";

	/**
	* apisite
	* String containing the hostname of the server to use for the Eve API
	*
	* @var String
	*/
	protected $apisite = "api.eve-online.com";	// The hostname of the Eve API
	
	/**
	* cache
	* Boolean of wether to cache information
	*
	* @see cache()
	*
	* @var Boolean default true
	*/
	protected $cache = true;					// Default Caching to on

	/**
	* cachedir
	* String containing the path to the cache directory
	*
	* @see setCacheDir()
	*
	* @var String
	*/
	protected $cachedir = "./xmlcache";			// Set default cache directory

	/**
	* cachetime
	* Integer containing the number of minutes to cache the file
	*
	* @see setCacheTime()
	*
	* @var int
	*/
	protected $cachetime = 60;			// Set default to cache for 60 minutes
	
	/**
	* characterID
	* OPTIONAL: The CharacterID to use for returning character specific data from the API
	* 
	* see @setCharacterID()
	*
	* @var String
	*/
	private $characterID="";			// Set the default characterID

	/**
	* debug
	* Boolean of wether to store debug information
	*
	* @see debug()
	*
	* @var Boolean default false
	*/
	public $debug = false;					// Default Debug to on
	
	/**
	* errMsg
	* Array containing all error messages
	*
	* @see addMsg()
	* @see printMsg()
	*
	* @var String
	*/
	public $errMsg = array();					// Setup a blank array to push error messages to.

	/**
	* userID
	* String containing the userID to use for the Eve API
	*
	* @see eveapi::__construct()
	* @see eveapi::setApiCredentials()
	*
	* @var String
	*/
	private $userID="";				// Set the default API userID


	/**
	* 
	* Constructor Method
	* @param string UserID
	* @param string apiKey
	* @param string characterID
	*
	*
	*/
	function __construct($userID = null, $apiKey = null, $characterID = null){
		if((!empty($userID)) && (!empty($apiKey))){
			$this->setApiCredentials($userID, $apiKey);
		}
		if(!empty($characterID)){
			$this->setCharacterID($characterID);
		}
	}
	
	/**
	*
	* addMsg
	* Adds a message to the errMsg array
	*
	* @param string type
	* @param string msg
	*
	*/
	function addMsg($type, $msg, $file, $line){
		if((!empty($type)) && (!empty($msg)) && (!empty($file)) && (!empty($line))){
			$this->debug(true);
			$error = array('type' => $type, 'msg' => $msg, 'file' => $file, 'line' => $line);
			$this->errMsg[] = $error;
			unset($error);
		}
	}
			
	/**
	*
	* cache
	* Sets the global cache flag on or off
	*
	* @param Boolean bool
	*
	* @return Boolean true on success. Defaults to true on invlid input
	*/
	function cache($bool){
		if(is_bool($bool)){
			$this->cache = $bool;
			return true;
		}
		$this->addMsg("cache Warning", "Non-boolean passed, defaulting cache to true", __FILE__, __LINE__);
		$this->cache = true;
	
	}
	
	/**
	*
	* debug
	* Sets the global debug flag on or off
	*
	* @param Boolean bool
	*
	* @return Boolean true on success. Defaults to true on invlid input
	*/
	function debug($bool){
		if(is_bool($bool)){
			$this->debug = $bool;
			return true;
		}
		$this->addMsg("debug Warning", "Non-boolean passed, defaulting debug to true", __FILE__, __LINE__);
		$this->debug = true;
	}
	
	/**
	*
	* getCacheFile
	* Gets the real location of the cache file on the local filesystem
	*
	* @param string path
	*
	* @return string @realpath
	*/
	function getCacheFile($path){
		$realpath = "";
		if (!empty($this->userID)){
			if (!empty($this->characterID)){
				$realpath = $this->cachedir . '/' . $this->userID . '/' . $this->characterID . $path;
			} else {
				$realpath = $this->cachedir . '/' . $this->userID . $path;
			}
		} else {
			$realpath = $this->cachedir . $path;
		}
		return $realpath;
	}
	
	/**
	*
	* isCached
	* Checks if the file from $path is already cached
	*
	* @param string path
	*
	* @return boolean
	* true if the file is cached, and within cahce time, false if not, or not accessible.
	*/
	function isCached($path){
		$cachefile = $this->getCacheFile($path);
		if(!$this->cache)
			return false;
		if (file_exists($cachefile)){
			$fp = fopen($cachefile, "r");
			
			if ($fp){
				$contents = fread($fp, filesize($cachefile));
				fclose($fp);
				
				// check cache
				$xml = new SimpleXMLElement($contents);
				
				$cachetime = (string) $xml->currentTime;
				$time = strtotime($cachetime);
				
				// get GMT time
				$timenow = time();
				$now = $timenow - date('Z', $timenow);
				
				// if now is an hour ahead of the cached time, pretend this file is not cached
				$minutes = $this->cachetime * 60;
				if ($now >= $time + $minutes){
					return false;
				}
				
				return true;
			} else {
				$this->addMsg("isCached Error", "Could not open file for writing: " . $path, __FILE__, __LINE__);
			}
		} else {
			return false;
			$this->addMsg("iscached Error", "File does not exist: " . $cachefile, __FILE__, __LINE__);
		}		
	}
	
	/**
	*
	* loadCache
	* Loads the cached XML
	*
	* @param string path
	*
	* @return string @contents of XML file
	*/
	function loadCache($path){
		// its cached, open it and use it
		$file = $this->getCacheFile($path);
		
		$fp = fopen($file, "r");
		if ($fp){
			$contents = fread($fp, filesize($file));
			fclose($fp);
		} else {
			if ($this->debug){
				$this->addMsg("loadCache Error", "Could not open file for reading: " . $path, __FILE__, __LINE__);
			}
		}
		
		return $contents;
	}

	/**
	*
	* printMsg
	* Prints error messages to the screen providing global debug is on.
	*
	* @return messages
	*/	
	function printMsg(){
		if($this->debug){
			foreach ($this->errMsg as $msg){
				echo ("<b>" . $msg['type'] . "</b> (".$msg['file'].":".$msg['line']."): " . $msg['msg'] . "</br>\n");
			}
		}
	}
	
	/**
	*
	* retreiveXML
	* Gets the XML from the EVE API
	*
	* @param string path
	* @param array extras
	*
	* path should be only the path to the file (e.g. /char/AssetList.xml.aspx)
	* extras should contain any additional variables that need to be passed int he URL e.g. 'characterID' => '1234'
	* 
	* @return mixed 
	*/
	function retreiveXML($path, $extras = null){
		if(!empty($path)){
			$params = array();
			if(!empty($extras))
				$params = array_merge($params, $extras);
			
			if((!empty($this->userID)) && (!empty($this->apiKey))){
				$params['userID'] = $this->userID;
				$params['apiKey'] = $this->apiKey;
			}
			
			if(!empty($this->characterID)){
				$params['characterID'] = $this->characterID;
			}
			if(!$this->isCached($path)){
				if (count($params) > 0)
					$poststring = http_build_query($params);
				else
					$poststring = "";
				// open connection to the api
				$fp = fsockopen($this->apisite, 80);
				if (!$fp){
					$this->addMsg("retreiveXML Error", "Could not connect to API URL", __FILE__, __LINE__);
				} else {
					// request the xml
					fputs ($fp, "POST " . $path . " HTTP/1.0\r\n");
					fputs ($fp, "Host: " . $this->apisite . "\r\n");
					fputs ($fp, "Content-Type: application/x-www-form-urlencoded\r\n");
					fputs ($fp, "User-Agent: PHPApi\r\n");
					fputs ($fp, "Content-Length: " . strlen($poststring) . "\r\n");
					fputs ($fp, "Connection: close\r\n\r\n");
					if (strlen($poststring) > 0)
						fputs ($fp, $poststring."\r\n");
					
					// retrieve contents
					$contents = "";
					while (!feof($fp)){
						$contents .= fgets($fp);
					}
					
					// close connection
					fclose($fp);
					$start = strpos($contents, "\r\n\r\n");
					if ($start !== FALSE){
						$contents = substr($contents, $start + strlen("\r\n\r\n"));
						
						// check if there's an error or not
						$xml = new SimpleXMLElement($contents);
						
						$error = (string) $xml->error;
						if (!empty($error)){
							$this->addMsg("retreiveXML Api", $error, __FILE__, __LINE__);
							
							if ($this->isCached($path)){
								return simplexml_load_string($this->loadCache($path));
							}
							
							return null;
						}
						
						if (!$this->isCached($path) && ($this->cache)){
							$this->store($contents, $this->getCacheFile($path));
						}
						
						return simplexml_load_string($contents);
					}
					
					$this->addMsg("retreiveXML Error", "Could not parse contents", __FILE__, __LINE__);
					
					return null;
				}
			} else {
				return simplexml_load_string($this->loadCache($path));
			}
		}
		
		$this->addMsg("retreiveXML Error", "Path is empty", __FILE__, __LINE__);
		
		return null;
	}
	
	/**
		
	*
	* setApiCredentials
	* Sets the api userID and apiKey to the requested values
	*
	* @param string userID
	* @param string apiKey
	* 
	* @return boolean true on success, false on fail (with error logged)
	*/
	function setApiCredentials($userID, $apiKey){
		if(!empty($userID) && !empty($apiKey)){
			$this->userID = $userID;
			$this->apiKey = $apiKey;
			return true;
		}
		$this->addMsg("setApiCredentials Error", "UserID or API Key not provided.", __FILE__, __LINE__);
		return false;
	}
	
	/**
	*
	* setCacheDir
	* Sets the Cache directory to be used - should be writable by (at least) the web user
	*
	* @param string path (relative to website root)
	* 
	* @return true on success, false on fail (with error logged).
	* on invalid path specified defaults to ./xmlcache and returns false
	*/
	function setCacheDir($path){
		if(file_exists($path) && (filetype($path) == "dir")){
			$this->cachedir = $path;
			$this->addMsg("setCacheDir Notice","Cache Updated to " . $path . " type: " . filetype($path), __FILE__, __LINE__);
			$perms = fileperms($path);
			if($perms[1] < 6){
				$this->addMsg("setCacheDir Error","No write permissions to " . $path . " defaulting to ./xmlcache", __FILE__, __LINE__);
				$this->cachedir = "./xmlcache";
				return;
			}
			return true;
		}
		$this->addMsg("setCacheDir Notice","Cache update to " . $path . " failed type: " . filetype($path) . " defaulting to ./xmlcache", __FILE__, __LINE__);
		$this->cachedir = "./xmlcache";
		return false;
	}
	
	/**
	*
	* setCharacterID
	* Sets the characterID to use for the API
	*
	* @param string characterID
	* 
	* @return true on success, false on fail (with error logged)
	*/
	function setCharacterID($characterID){
		$characterID = (int)$characterID;
		if(!empty($characterID) && ($characterID > 0)){
			$this->characterID = $characterID;
		} else {
			$this->addMsg("setCharacterID Error", "Invlid Character ID (".$characterID.")passed", __FILE__, __LINE__);
		}
	}
	
	/**
	*
	* store
	* Stores the cached XML into it's path 
	*
	* @param string contents
	* @param string path
	*
	* 
	*/
	function store($contents, $path){
		if (!file_exists(dirname($path))){
			mkdir(dirname($path), 0777, true);
		}
		
		$fp = fopen($path, "w");
		
		if ($fp){
			fwrite($fp, $contents);
			fclose($fp);
		} else {
			if ($this->debug){
				$this->addMsg("store Error", "Could not open file for writing: " . $path, __FILE__, __LINE__);
			}
		}
	}
	
}
?>